//---------------------------------------------------------------------------
#include <eic.h>
#include <vcl.h>
#pragma hdrstop

#include "CMForm.h"
#pragma link "CForm"
#pragma package(smart_init)
//---------------------------------------------------------------------------
#define macro_pListApplications(i)    ((TInfosApplication *)pListApplications->Items[i])
#define macro_IndexLastApplication    (pListApplications->Count-1)
#define macro_pListApplications_last  macro_pListApplications(macro_IndexLastApplication)
//---------------------------------------------------------------------------
static TList      *pListApplications = NULL;
static TStatusBar *pMainStatusBar    = NULL;
static TMainMenu  *pMainMenu         = NULL;
static bool        bMainTabEnter     = true;
static int         nCurrentApp       = -1; // -1 : pas d'application en cours
//---------------------------------------------------------------------------
// Renvoie le premier composant trouvé TMainMenu d'une form
TMainMenu *__fastcall FindTMainMenuComponent(TForm *pFormApp)
{
  for(int i=pFormApp->ComponentCount-1; i>=0; i--) {
    if ( dynamic_cast<TMainMenu *>( pFormApp->Components[i]) && ( pFormApp->Components[i]->Tag==0))
      return dynamic_cast<TMainMenu *>(pFormApp->Components[i]);
  }
  return NULL;
}
//---------------------------------------------------------------------------
// Renvoie le premier composant trouvé TStatusBar d'une form
TStatusBar *__fastcall FindTStatusBar(TForm *pFormApp)
{
  for(int i=pFormApp->ComponentCount-1; i>=0; i--) {
    if (dynamic_cast<TStatusBar *>(pFormApp->Components[i]))
      return dynamic_cast<TStatusBar *>(pFormApp->Components[i]);
  }
  return NULL;
}
//---------------------------------------------------------------------------
// Renvoie un pointeur sur les informations d'une form
TInfosApplication *__fastcall GetInfosApplication(TForm *pForm)
{
  TInfosApplication *infosApp;

  for(int i=pListApplications->Count-1; i>=0; i--) {
    infosApp = (TInfosApplication *)pListApplications->Items[i];
    if (infosApp->pAppMainForm==pForm) return infosApp;
  }
  return NULL;
}
//---------------------------------------------------------------------------
// Renvoie un numéro de groupe
int __fastcall GetGroupNumber(TForm *pForm)
{
  TInfosApplication *infosApp;

  if (!pForm) {
    // Créer un nouveau numéro de groupe
    int max = -1;
    for(int j=pListApplications->Count-1; j>=0; j--) {
      infosApp = (TInfosApplication *)pListApplications->Items[j];
      if (infosApp->nGroup>max) max = infosApp->nGroup;
    }
    return (++max);
  // Retourne un numéro de groupe déjà existant
  } else return GetInfosApplication(pForm)->nGroup;
}
//---------------------------------------------------------------------------
// Affecte le parent d'une StatusBar
void __fastcall SetStatusBar( TStatusBar *pStatusBar, TWinControl *newParent)
{
  if( pMainStatusBar && (pMainStatusBar!=pStatusBar))
      pMainStatusBar->Parent = NULL;

  if( pStatusBar)
      pStatusBar->Parent = newParent;
}
//---------------------------------------------------------------------------
// Détermine la hauteur maximum d'une form
/*inline int __fastcall SetApplicationHeight(TStatusBar *pStatusBar)
{
  TStatusBar *pSBar = pStatusBar ? pStatusBar : pMainStatusBar;

  return (pSBar ? CMainForm->ClientHeight - pSBar->Height
                : CMainForm->ClientHeight);
}*/
inline int __fastcall SetApplicationHeight()
{
  TStatusBar *pSBar = macro_pListApplications_last->pStatusBar;//FindTStatusBar( CMainForm);

  return( pSBar ? CMainForm->ClientHeight - pSBar->Height
                : CMainForm->ClientHeight);
}//---------------------------------------------------------------------------
// Ajoute une application dans la fenêtre principale
TInfosApplication *__fastcall CMainForm_AddApplicationGroup(TForm *pForm, TForm *pFormGrp)
{
  ASSERT(pForm);

  try {
    TMainMenu         *pMenu;
    TInfosApplication *infosApp;

    // Cache la fenêtre courante (Visible = false)
    // et cache sa propre StatusBar
    if (nCurrentApp!=-1) {
      infosApp = ( TInfosApplication*)pListApplications->Items[nCurrentApp];
      infosApp->pAppMainForm->Visible = false;
      SetStatusBar( infosApp->pStatusBar, NULL);
    } else {
      CMainForm->SaveCaption = CMainForm->Caption;
      pMainStatusBar         = FindTStatusBar(CMainForm);
      pMainMenu              = FindTMainMenuComponent(CMainForm);
      bMainTabEnter          = CMainForm->TabEnter;
    }
    // Initialisation de la structure
    infosApp               = new TInfosApplication;
    infosApp->pAppMainForm = pForm;
    infosApp->pAppMenu     = FindTMainMenuComponent(pForm);
    infosApp->pOldParent   = pForm->Parent;
    infosApp->pStatusBar   = FindTStatusBar(pForm);
    infosApp->nGroup       = GetGroupNumber(pFormGrp);
    // Modification des propriétés de la fenêtre pour
    // qu'elle soit fille de cet objet
    nCurrentApp            = pListApplications->Add( infosApp);
    if( infosApp->pAppMenu) {
      //++pMenu = FindTMainMenuComponent(CMainForm); ASSERT(pMenu);
      //++pMenu->Merge(infosApp->pAppMenu);
      infosApp->pAppMainForm->Menu = NULL;
      CMainForm->Menu = infosApp->pAppMenu;
    }
    SetStatusBar( infosApp->pStatusBar, CMainForm);
    pForm->Position    = poDesigned;
    pForm->BorderStyle = bsNone;
    pForm->Top         = 0;
    pForm->Left        = 0;
    pForm->Height      = SetApplicationHeight(/*infosApp->pStatusBar*/);
    pForm->Width       = CMainForm->ClientWidth;
    pForm->Parent      = CMainForm;
    CMainForm_ChangeCaption(pForm->Caption);
    CMainForm->TabEnter = dynamic_cast< CForm*>( infosApp->pAppMainForm) ? (( CForm*)infosApp->pAppMainForm)->TabEnter : false;

    // Donne la main au premier control de la nouvelle form ajoutée
    ::PostMessage( pForm->Handle, WM_NEXTDLGCTL, pForm->ActiveControl ? ( WPARAM)pForm->ActiveControl->Handle : NULL, TRUE);

    return infosApp;
  } catch ( Exception &e) {
    ShowMessage( e.Message);
    return NULL;
  }
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_AddApplicationNewGrp(TForm *pForm, TRemoveGroupEvent pEvent, void *pDatas)
{
  TInfosApplication *infosApp;
  infosApp = CMainForm_AddApplicationGroup( pForm, NULL);
  infosApp->OnRemoveGroup = pEvent;
  infosApp->pParam        = pDatas;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_AddApplication(TForm *pForm)
{
  TInfosApplication *infosApp;
  TInfosApplication *infosAppLast = macro_pListApplications_last;

  ASSERT(nCurrentApp!=-1);
  infosApp = CMainForm_AddApplicationGroup(pForm, infosAppLast->pAppMainForm);
  infosApp->OnRemoveGroup = infosAppLast->OnRemoveGroup;
  infosApp->pParam        = infosAppLast->pParam;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_ChangeCaption(const AnsiString& newCaption)
{
  if (nCurrentApp!=-1) {
    macro_pListApplications(nCurrentApp)->pAppMainForm->Caption = newCaption;
    CMainForm->Caption = newCaption;
  } else CMainForm->Caption = CMainForm->SaveCaption;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_DeleteApplication(int nIndex)
{
  TInfosApplication *infosApp = macro_pListApplications(nIndex);
  TMainMenu         *pMenu;

  pListApplications->Delete(nIndex);
  // Recherche s'il existe une application de même groupe
  for(int j=pListApplications->Count-1; j>=0; j--) {
    TInfosApplication *infosTmp = macro_pListApplications(j);
    if (infosTmp->nGroup==infosApp->nGroup) goto lblHaveBrother;
  }
  // Aucune autre application dans le groupe, on appelle
  // l'événement OnRemoveGroup
  if (infosApp->OnRemoveGroup) infosApp->OnRemoveGroup( true);

lblHaveBrother:
  infosApp->pAppMainForm->Parent = infosApp->pOldParent;
  SetStatusBar( infosApp->pStatusBar, infosApp->pAppMainForm);
  // Enlève la fenêtre de l'application
  if (infosApp->pAppMenu) {
    //++pMenu = FindTMainMenuComponent(CMainForm); ASSERT(pMenu);
    //++pMenu->Unmerge(infosApp->pAppMenu);
    CMainForm->Menu = NULL;
    infosApp->pAppMainForm->Menu = infosApp->pAppMenu;
  }
  delete infosApp;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_RemoveApplicationsGroup(TForm *pForm /* = NULL */)
{
  ASSERT(nCurrentApp!=-1);
  if (nCurrentApp==-1) return;

  TInfosApplication *infosApp;
  int                nGrp;

  CMainForm->DestroyChildWin = true;

  if (!pForm) pForm = macro_pListApplications_last->pAppMainForm;
  infosApp                        = GetInfosApplication(pForm);
  nGrp                            = infosApp->nGroup;
  infosApp->pAppMainForm->Visible = false;

  ASSERT(nGrp != -1);
  for(int i=pListApplications->Count-1; i>=0; i--) {
    if (macro_pListApplications(i)->nGroup==nGrp)
      CMainForm_DeleteApplication(i);
  }

  CMainForm_ActiveApplication(pListApplications->Count-1);
  CMainForm->DestroyChildWin = false;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_SetNewMainMenu( TForm *pForm, TMainMenu *pNewMenu)
{
  TInfosApplication *infosApp = GetInfosApplication( pForm);
  TMainMenu         *pMenu    = FindTMainMenuComponent(CMainForm); ASSERT(pMenu);
  // Si la fenêtre contenait déjà un menu, on le supprimer
  if (infosApp->pAppMenu) {
    //++pMenu->Unmerge(infosApp->pAppMenu);
    ASSERT( dynamic_cast< TForm*>( pNewMenu->Owner));
    (( TForm*)pNewMenu->Owner)->Menu = NULL;
    CMainForm->Menu = NULL;
  }
  // Et on remplace par le nouveau
  if ( pNewMenu) {
    //++pMenu->Merge( pNewMenu);
    CMainForm->Menu = pNewMenu;
  }
  infosApp->pAppMenu = pNewMenu;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_SetNewStatusBar( TForm *pForm, TStatusBar *pStatusBar)
{
  TInfosApplication *infosApp = GetInfosApplication( pForm);
  SetStatusBar( infosApp->pStatusBar, infosApp->pOldParent);
  infosApp->pStatusBar = pStatusBar;
  SetStatusBar( infosApp->pStatusBar, CMainForm);
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_RemoveApplication(TForm *pForm)
{
  TInfosApplication *infosApp;

  ASSERT(pForm);

  CMainForm->DestroyChildWin = true;
  // Recherche de la fenêtre à retirer
  for(int i=pListApplications->Count-1; i>=0; i--) {
    infosApp = (TInfosApplication *)pListApplications->Items[i];
    if (infosApp->pAppMainForm!=pForm) continue;

    CMainForm_DeleteApplication(i);
    CMainForm_ActiveApplication(pListApplications->Count-1);
    break;
  }
  CMainForm->DestroyChildWin = false;
}
//---------------------------------------------------------------------------
void __fastcall CMainForm_ActiveApplication(int index)
{
  TInfosApplication *infosApp;
  TMainMenu         *pMenu;

  if(( nCurrentApp=index)>=0) {
    ASSERT((index>=0) && (index<pListApplications->Count));
    // Active la nouvelle application
    infosApp = macro_pListApplications(index);
    infosApp->pAppMainForm->Visible = true;
    CMainForm_ChangeCaption(infosApp->pAppMainForm->Caption);
    SetStatusBar( infosApp->pStatusBar, CMainForm);
    if (infosApp->pAppMenu) {
      //++pMenu = FindTMainMenuComponent(CMainForm); ASSERT(pMenu);
      //++pMenu->Merge(infosApp->pAppMenu);
      CMainForm->Menu = infosApp->pAppMenu;
    }
    infosApp->pAppMainForm->Height = SetApplicationHeight();
    CMainForm->TabEnter = dynamic_cast< CForm*>( infosApp->pAppMainForm) ? (( CForm*)infosApp->pAppMainForm)->TabEnter : false;
  } else {
    CMainForm_ChangeCaption(EmptyStr);
    SetStatusBar( pMainStatusBar, CMainForm);
    CMainForm->Menu = NULL;
    CMainForm->Menu = pMainMenu;
    CMainForm->TabEnter = bMainTabEnter;
  }
}
//---------------------------------------------------------------------------
CForm *__fastcall CMainForm_GetCurrentForm()
{
  return dynamic_cast<CForm*>( macro_pListApplications_last->pAppMainForm);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour être sûr que les composants créés ne
// contiennent aucune fonction virtuelle pure.
//

static inline void ValidCtrCheck(CEICMainForm *)
{
    new CEICMainForm(NULL);
}
//---------------------------------------------------------------------------
__fastcall CEICMainForm::CEICMainForm(TComponent* Owner)
    : CEICForm(Owner)
{
  m_pOldCloseQueryEvent = OnCloseQuery;
  OnCloseQuery          = EvOnCloseQuery;
  pListApplications     = new TList;
  EICPosition           = posInherrited;
  DestroyChildWin       = false;
}
//---------------------------------------------------------------------------
__fastcall CEICMainForm::~CEICMainForm()
{
  delete pListApplications; pListApplications = NULL;
}
//---------------------------------------------------------------------------
void __fastcall CEICMainForm::EvOnCloseQuery(TObject* Sender, bool &CanClose)
{
  // Si aucune application n'ext active, on ferme la fenêtre
  if (nCurrentApp==-1) {
    if (m_pOldCloseQueryEvent) {
      m_pOldCloseQueryEvent(Sender, CanClose);
      return;
    } else { CanClose=true; return; }
  }

  TInfosApplication *infosApp = (TInfosApplication *)pListApplications->Items[nCurrentApp];
  if (infosApp->pAppMainForm->CloseQuery()) infosApp->pAppMainForm->Close();
  CanClose = false;
}
//---------------------------------------------------------------------------
void __fastcall CEICMainForm::EvApplicationOnHint(TObject *Sender)
{
  TInfosApplication *infosApp;
  TStatusBar        *pStatusBar;

  if (nCurrentApp==-1) {
    // Aucune application de charger
    // On prend la status barre de la fenêtre principale
    pStatusBar = FindTStatusBar(CMainForm);
  } else {
    // Si une application existe déjà, on vérifie qu'elle contient
    // bien une barre de status et on lui affecte le Hint
    infosApp = (TInfosApplication *)pListApplications->Items[nCurrentApp];
    pStatusBar = infosApp->pStatusBar;
  }

  // Si aucune barre de status n'a été trouvé, on ne fait rien
  if (!pStatusBar) return;

  // Si c'est une status barre à 1 seul panel on modifie la propriété SimpleText
  // sinon on modifie la propriété Panels->Items[0]->Text
  if (pStatusBar->SimplePanel) pStatusBar->SimpleText = GetLongHint(Application->Hint);
  else pStatusBar->Panels->Items[0]->Text = GetLongHint(Application->Hint);
}
//---------------------------------------------------------------------------
void __fastcall CEICMainForm::WMWindowPosChanged(TWMWindowPosChanged &Msg)
{
  CEICForm::Dispatch(&Msg);
  // Retaille l'application actuellement sélectionnée
  if ((nCurrentApp==-1) || DestroyChildWin) return;

  //TInfosApplication *infosApp    = (TInfosApplication *)pListApplications->Items[nCurrentApp];
  //infosApp->pAppMainForm->Height = SetApplicationHeight(infosApp->pStatusBar);
  //infosApp->pAppMainForm->Width  = CMainForm->ClientWidth;
  Redimensionner();

}
//---------------------------------------------------------------------------
void __fastcall CEICMainForm::WMEnable(TWMEnable &Msg)
{
  CEICForm::Dispatch(&Msg);

/*
  if (( nCurrentApp==-1) || !pListApplications->Count) return;
  TInfosApplication *infosApp = (TInfosApplication *)pListApplications->Items[nCurrentApp];
  if (infosApp->pAppMenu) {
    TMainMenu *pMenu = FindTMainMenuComponent(CMainForm); ASSERT(pMenu);
               pMenu->Merge(infosApp->pAppMenu);
  }
*/
}
//---------------------------------------------------------------------------
namespace Cmform
{
/*
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(CEICMainForm)};
        RegisterComponents("EIC Outils", classes, 0);
    }
*/
}
//---------------------------------------------------------------------------
void __fastcall CEICMainForm::Redimensionner()
{
  TInfosApplication *infosApp;
  for( int i=pListApplications->Count-1; i>=0; i--) {
    infosApp = ( TInfosApplication*)pListApplications->Items[i];
    infosApp->pAppMainForm->Height = SetApplicationHeight(/*infosApp->pStatusBar*/);
    infosApp->pAppMainForm->Width  = CMainForm->ClientWidth;
    }
}

